package com.peakmain.wanandroid.netmodule.net.http;


import android.app.Application;
import android.content.Context;

import com.blankj.utilcode.util.NetworkUtils;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.peakmain.wanandroid.netmodule.net.http.callback.RequestCallBack;
import com.peakmain.wanandroid.netmodule.net.http.cookie.CookieJarImpl;
import com.peakmain.wanandroid.netmodule.net.http.cookie.store.PersistentCookieStore;
import com.peakmain.wanandroid.netmodule.net.http.interceptor.LoggerInterceptor;
import com.peakmain.wanandroid.netmodule.net.http.params.GetRequest;
import com.peakmain.wanandroid.netmodule.net.http.params.ParamsHeaders;
import com.peakmain.wanandroid.netmodule.net.http.params.Platform;
import com.peakmain.wanandroid.netmodule.net.http.params.PostRequest;
import com.peakmain.wanandroid.netmodule.net.http.params.RequestParams;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.OkHttpClient;

/**
 * author ：Peakmain
 * version : 1.0
 * createTime：2020/2/22
 * mail:2726449200@qq.com
 * describe：okHttp 管理
 */
public class OkHttpManager {
    private static final int TIME_OUT = 10;//超时 秒作为单位 SECONDS
    private static final int READ_TIME_OUT = 30;//超时 秒作为单位 SECONDS
    private static Application context;
    private volatile static OkHttpManager mInstance;
    private OkHttpClient.Builder okHttpClientBuilder;
    private OkHttpClient mOkHttpClient;
    private Platform mPlatform;
    private RequestParams mCommonParams;                     //全局公共请求参数
    private ParamsHeaders mCommonHeaders;                   //全局公共请求头
    private CookieJarImpl cookieJar;
    /**
     * 必须在全局Application先调用，获取context上下文，否则缓存无法使用
     * @param app 全局
     * @param url  主机请求地址
     */
    public static void init(Application app,String url) {
        context = app;
        HttpUtil.getInstance().setBaseUrl(url);
    }
    private OkHttpManager(OkHttpClient okHttpClient) {
        if (okHttpClient == null) {
            mOkHttpClient = new OkHttpClient();
        } else {
            mOkHttpClient = okHttpClient;
        }
        okHttpClientBuilder = mOkHttpClient.newBuilder();
        //允许cookie的自动化管理
        cookieJar = new CookieJarImpl(new PersistentCookieStore());
        okHttpClientBuilder.cookieJar(cookieJar);
        okHttpClientBuilder.pingInterval(10, TimeUnit.SECONDS);
        okHttpClientBuilder.hostnameVerifier(new DefaultHostnameVerifier());
        okHttpClientBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
        okHttpClientBuilder.readTimeout(READ_TIME_OUT, TimeUnit.SECONDS);
        okHttpClientBuilder.writeTimeout(READ_TIME_OUT, TimeUnit.SECONDS);
        mPlatform = Platform.get();
    }

    private static OkHttpManager initClient(OkHttpClient okHttpClient) {
        if (mInstance == null) {
            synchronized (OkHttpManager.class) {
                if (mInstance == null) {
                    mInstance = new OkHttpManager(okHttpClient);
                }
            }
        }
        return mInstance;
    }

    public static OkHttpManager getInstance() {
        return initClient(null);
    }

    public Executor getDelivery() {
        return mPlatform.defaultCallbackExecutor();
    }

    public OkHttpClient getOkHttpClient() {
        return okHttpClientBuilder.build();
    }

    /**
     * get请求
     */
    public static GetRequest get() {
        return new GetRequest();
    }

    /**
     * post请求
     */
    public static PostRequest post() {
        return new PostRequest();
    }

    /**
     * 添加全局公共请求参数
     */
    public OkHttpManager addCommonParams(RequestParams commonParams) {
        if (mCommonParams == null) {
            mCommonParams = new RequestParams();
        }
        mCommonParams.put(commonParams);
        return this;
    }

    /**
     * 添加全局公共请求参数
     */
    public OkHttpManager addCommonHeaders(ParamsHeaders commonHeaders) {
        if (mCommonHeaders == null) {
            mCommonHeaders = new ParamsHeaders();
        }
        mCommonHeaders.put(commonHeaders);
        return this;
    }

    /** 获取全局公共请求参数 */
    public RequestParams getCommonParams() {
        return mCommonParams;
    }

    /** 获取全局公共请求头 */
    public ParamsHeaders getCommonHeaders() {
        return mCommonHeaders;
    }




    /**
     * 获取全局上下文
     */
    public static Context getContext() {
        if (context == null)
            throw new IllegalStateException("请先在全局Application中调用 OkHttpManager.init(context) 初始化！");
        return context;
    }

    /**
     * 调试模式
     */
    public OkHttpManager debug(boolean isDebug) {
        okHttpClientBuilder.addInterceptor(new LoggerInterceptor(isDebug));
        if (isDebug) {
            okHttpClientBuilder.addNetworkInterceptor(new StethoInterceptor());
        }
        return this;
    }

    /**
     * 此类是用于主机名验证的基接口。 在握手期间，如果 URL 的主机名和服务器的标识主机名不匹配，
     * 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。
     * 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的，则返回 true
     */
    public class DefaultHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return (hostname.endsWith("thedoc.cn")||hostname.endsWith("lifewow.io"));
        }
    }

    /**
     * https的全局访问规则
     *
     * @param hostnameVerifier
     */
    public OkHttpManager setHostnameVerifier(HostnameVerifier hostnameVerifier) {
        okHttpClientBuilder.hostnameVerifier(hostnameVerifier);
        return this;
    }

    /**
     * https的全局自签名证书
     *
     * @param factory
     */
    public OkHttpManager setCertificates(SSLSocketFactory factory) {
        okHttpClientBuilder.sslSocketFactory(factory);
        return this;
    }

    /**
     * 设置全局自签名双向认证证书
     * @return
     */
    public OkHttpManager setsslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager){
        okHttpClientBuilder.sslSocketFactory(sslSocketFactory,trustManager);
        return this;
    }

    /**
     * 手动设置cookie
     * @param cookieJar
     */
    public void setCookieJar(CookieJarImpl cookieJar){
        if(cookieJar == null )return;
        okHttpClientBuilder.cookieJar(cookieJar);
    }

    /**
     * 清除Cookie
     */
    public void removeAllCookie() {
        if (cookieJar == null) {
            return;
        }
        cookieJar.getCookieStore().removeAllCookie();
    }

    /**
     * 根据Tag取消请求
     */
    public void cancelTag(Object tag) {
        for (Call call : getOkHttpClient().dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : getOkHttpClient().dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    /**
     * 下载文件的okHttp实例
     * @return
     */
    public static OkHttpClient getDownloadInstance(){
        OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
                .addNetworkInterceptor(new StethoInterceptor())
                .addInterceptor(new LoggerInterceptor(true))
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .build();
        return okHttpClient;
    }



    /**
     * 执行okHttp 请求
     *
     * @param requestCall okHttp调用
     * @param callback    结果回调
     */
    public <T> void execute(final RequestCall requestCall, RequestCallBack<T> callback) {
        OkHttpResponse response = new OkHttpResponse(requestCall, callback);
        //校验是否网络连接
        if(NetworkUtils.isAvailableByPing()){
            response.executeOkHttp();
        }else {
            ResponseCode responseCode = new ResponseCode();
            responseCode.setCode(ResponseCode.NETWORK_ERROR);
            if(callback != null){
                callback.onAfter(requestCall.getOkHttpRequest().getId());
                callback.onError(responseCode,null,requestCall.getOkHttpRequest().getId());
            }
        }
    }

    public static void setInstance(OkHttpManager mInstance) {
        OkHttpManager.mInstance = mInstance;
    }

    public static OkHttpManager getmInstance() {
        return mInstance;
    }

}
